package aliasMatching.view;

import aliasMatching.controller.EqualityActions;
import aliasMatching.controller.ProgressCellRenderer;
import aliasMatching.controller.TableActions;
import aliasMatching.model.MyTableModel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.swing.Action;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.Renderer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumnModel;

import prefuse.Constants;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.ItemAction;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.DataShapeAction;
import prefuse.action.assignment.FontAction;
import prefuse.action.filter.GraphDistanceFilter;
import prefuse.action.layout.AxisLabelLayout;
import prefuse.action.layout.AxisLayout;
import prefuse.action.layout.graph.ForceDirectedLayout;
import prefuse.activity.Activity;
import prefuse.controls.ControlAdapter;
import prefuse.controls.DragControl;
import prefuse.controls.FocusControl;
import prefuse.controls.NeighborHighlightControl;
import prefuse.controls.PanControl;
import prefuse.controls.WheelZoomControl;
import prefuse.controls.ZoomControl;
import prefuse.controls.ZoomToFitControl;
import prefuse.data.Graph;
import prefuse.data.Table;
import prefuse.data.Tuple;
import prefuse.data.event.TupleSetListener;
import prefuse.data.io.DataIOException;
import prefuse.data.io.sql.ConnectionFactory;
import prefuse.data.io.sql.DatabaseDataSource;
import prefuse.data.query.NumberRangeModel;
import prefuse.data.query.SearchQueryBinding;
import prefuse.data.search.PrefixSearchTupleSet;
import prefuse.data.search.SearchTupleSet;
import prefuse.data.tuple.TupleSet;
import prefuse.render.AbstractShapeRenderer;
import prefuse.render.AxisRenderer;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.LabelRenderer;
import prefuse.render.RendererFactory;
import prefuse.render.ShapeRenderer;
import prefuse.util.ColorLib;
import prefuse.util.FontLib;
import prefuse.util.force.ForceSimulator;
import prefuse.util.ui.JForcePanel;
import prefuse.util.ui.JSearchPanel;
import prefuse.util.ui.UILib;
import prefuse.visual.NodeItem;
import prefuse.visual.VisualGraph;
import prefuse.visual.VisualItem;
import prefuse.visual.VisualTable;
import prefuse.visual.expression.VisiblePredicate;
import prefuse.visual.sort.ItemSorter;
import rdfparser.db.DBConnection;

/**
 *
 * @author amendrashrestha
 * This is the main class of application. The graph, table and search panel are
 * created and added in the main frame.
 *
 */
public class BoardGraphView extends JPanel {

    public static JFrame frame, mainFrame;
    private static final String treeGraph = "graph";
    private static final String nodes = "graph.nodes";
    private static final String edges = "graph.edges";
    public static final String label = "Name";
    static Table tableNodes = null;
    static Table tableEdges = null;
    static Connection con = null;
    static DatabaseDataSource datasource = null;
    private Visualization m_vis;
    static Rectangle maxBounds;
    public List userIDList, userNameList;
    JTable display_table;
    private JScrollPane scrollPane;
    private List percentageList;
    private List postTimeList;
    private List clickedUserList;
    MyTableModel mdl;
    Action friendAxn, threadAxn, timeAxn, nameAxn, stylometricAxn, newAxn, exitAxn, chartAxn;
    protected Action avgPercentageAxn, allpostTimeGraphAxn;
    private JPopupMenu popUpMenu;
    private JMenuItem popUpItem;
    private JPopupMenu tablePopupMenu;
    private JMenuItem tablePopupItem;
    Display display;
    JToolBar bar;
    JPanel fpanel, rightPanel;

    public BoardGraphView(Graph graph) {
        super(new BorderLayout());
        fpanel = new JPanel();
        // create a new, empty visualization for our data
        m_vis = new Visualization();
        maxBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().
                getMaximumWindowBounds();
        int screenWidth = maxBounds.width;
        userIDList = new ArrayList();
        userNameList = new ArrayList();
        mdl = new MyTableModel();
        bar = new JToolBar();
        bar.setBackground(Color.white);
        bar.setFloatable(false);

        /**
         * Image icons
         */
        
        ImageIcon newIcon = new ImageIcon(getClass().getResource("/Utilities/new.png"));
        ImageIcon chartIcon = new ImageIcon(getClass().getResource("/Utilities/chart.png"));
        ImageIcon threadIcon = new ImageIcon(getClass().getResource("/Utilities/thread.png"));
        ImageIcon timeIcon = new ImageIcon(getClass().getResource("/Utilities/time.png"));
        ImageIcon nameIcon = new ImageIcon(getClass().getResource("/Utilities/name.png"));
        ImageIcon styloIcon = new ImageIcon(getClass().getResource("/Utilities/stylo.png"));
        ImageIcon friendIcon = new ImageIcon(getClass().getResource("/Utilities/friend.png"));
        ImageIcon exitIcon = new ImageIcon(getClass().getResource("/Utilities/exit.png"));
        /**Creating actions for popUp Menu*/
        newAxn = new EqualityActions("New", "New", userIDList, userNameList, mdl, newIcon, "New");
        chartAxn = new EqualityActions("Chart", "Chart", userIDList, userNameList, mdl, chartIcon, "Time Chart");
        threadAxn = new EqualityActions("Thread", "ThreadEquality", userIDList, userNameList, mdl, threadIcon, "Thread");
        timeAxn = new EqualityActions("Time", "TimeEquality", userIDList, userNameList, mdl, timeIcon, "Time");
        nameAxn = new EqualityActions("Name", "NameEquality", userIDList, userNameList, mdl, nameIcon, "Name");
        stylometricAxn = new EqualityActions("Stylometric", "StylometricEquality",
                userIDList, userNameList, mdl, styloIcon, "Stylometric");
        friendAxn = new EqualityActions("Friend", "FriendEquality", userIDList, userNameList, mdl, friendIcon, "Friend");
        exitAxn = new EqualityActions("Exit", "Exit", null, null, null, exitIcon, "Exit");

        // register the data with a visualization
        //adds graph to visualization and sets renderer label field
        setGraph(graph);

        // fix selected focus nodes
        TupleSet focusGroup = m_vis.getGroup(Visualization.FOCUS_ITEMS);
        focusGroup.addTupleSetListener(new TupleSetListener() {

            public void tupleSetChanged(TupleSet ts, Tuple[] add, Tuple[] rem) {
                for (int i = 0; i < rem.length; ++i) {
                    ((VisualItem) rem[i]).setFixed(false);
                }
                for (int i = 0; i < add.length; ++i) {
                    ((VisualItem) add[i]).setFixed(false);
                    ((VisualItem) add[i]).setFixed(true);
                }
                if (ts.getTupleCount() == 0) {
                    ts.addTuple(rem[0]);
                    ((VisualItem) rem[0]).setFixed(false);
                }
                m_vis.run("draw");
            }
        });

        //the seach items focus group
        SearchTupleSet search = new PrefixSearchTupleSet();
        m_vis.addFocusGroup(Visualization.SEARCH_ITEMS, search);
        // --------------------------------------------------------------------
        // create actions to process the visual data
        int hops = 30;
        final GraphDistanceFilter filter = new GraphDistanceFilter(treeGraph, hops);
        ColorAction fill = new ColorAction(nodes, VisualItem.FILLCOLOR, ColorLib.rgb(255, 255, 255));
        fill.add("ingroup('_search_')", ColorLib.rgb(255, 0, 0));
        fill.add(VisualItem.FIXED, ColorLib.rgb(0, 191, 255));
        fill.add(VisualItem.HIGHLIGHT, ColorLib.rgb(205, 133, 0));

        ItemAction textColor = new TextColorAction(nodes);
        m_vis.putAction("textColor", textColor);

        FontAction fonts = new FontAction(nodes, FontLib.getFont("Tahoma", 14));
        ActionList draw = new ActionList();
        draw.add(filter);
        draw.add(fill);
        draw.add(fonts);
        draw.add(textColor);
        draw.add(new ColorAction(nodes, VisualItem.STROKECOLOR, ColorLib.rgb(0, 0, 0)));
        draw.add(new ColorAction(nodes, VisualItem.TEXTCOLOR, ColorLib.rgb(255, 255, 255)));
        /**
         * Stroke of edges
         */
        //draw.add(new ColorAction(edges, VisualItem.FILLCOLOR, ColorLib.gray(200)));
        //draw.add(new ColorAction(edges, VisualItem.STROKECOLOR, ColorLib.gray(200)));
        ActionList animate = new ActionList(Activity.INFINITY);
        animate.add(new ForceDirectedLayout(treeGraph, true));
        animate.add(fill);
        animate.add(fonts);
        animate.add(textColor);
        animate.add(new RepaintAction());
        // finally, we register our ActionList with the Visualization.
        // we can later execute our Actions by invoking a method on our
        // Visualization, using the name we've chosen below.
        m_vis.putAction("draw", draw);
        m_vis.putAction("layout", animate);
        m_vis.runAfter("draw", "layout");
        // --------------------------------------------------------------------
        // set up a display to show the visualization
        //JPanel graphDisplay = new JPanel(new BorderLayout());
        display = new Display(m_vis);
        display.setSize(maxBounds.width, maxBounds.height);

        //display.setSize(800, 800);
        display.pan(600, 400);
        display.setForeground(Color.GRAY);
        display.setBackground(Color.WHITE);
        // main display controls
        display.addControlListener(new FocusControl(1));
        display.addControlListener(new DragControl());
        display.addControlListener(new PanControl());
        display.addControlListener(new ZoomControl());
        display.addControlListener(new WheelZoomControl());
        //display.addControlListener(new ZoomToFitControl());
        NeighborHighlightControl neighbour = new NeighborHighlightControl();
        display.addControlListener(neighbour);
        neighbour.setHighlightWithInvisibleEdge(true);

        display.setCustomToolTip(new javax.swing.JToolTip());
        display.addControlListener(new HoverNode());
        display.addControlListener(new itemClick());

        display.add(setPopUpMenu(new Action[]{newAxn, chartAxn, threadAxn, friendAxn, timeAxn, nameAxn, stylometricAxn}));

        setNewAction(newAxn);
        setChartAction(chartAxn);
        setThreadAction(threadAxn);
        setTimeAction(timeAxn);
        setFriendAction(friendAxn);
        setNameAction(nameAxn);
        setStylometricAction(stylometricAxn);
        setExitAction(exitAxn);

        display.setForeground(Color.GRAY);
        display.setBackground(Color.WHITE);
        rightPanel = new JPanel();
        rightPanel.add(display, BorderLayout.NORTH);
        // --------------------------------------------------------------------
        // launch the visualization
        // create a panel for editing force values
        //ForceSimulator fsim = ((ForceDirectedLayout) animate.get(0)).getForceSimulator();
        //JForcePanel fpanel = new JForcePanel(fsim);
        fpanel.setBackground(Color.white);

        //fpanel.add(createToolPane());

        //search query binding and the searh panel
        SearchQueryBinding sq = new SearchQueryBinding((Table) m_vis.getGroup(nodes), label,
                (SearchTupleSet) m_vis.getGroup(Visualization.SEARCH_ITEMS));
        JSearchPanel searchPanel = sq.createSearchPanel();
        searchPanel.setShowResultCount(true);
        searchPanel.setMaximumSize(new Dimension(420, 20));
        searchPanel.setFont(FontLib.getFont("Tahoma", Font.PLAIN, 11));
        Box df = new Box(BoxLayout.Y_AXIS);
        df.add(searchPanel);
        df.setBorder(BorderFactory.createTitledBorder("Search"));
        JPanel topPanel = new JPanel(new BorderLayout());
        topPanel.setPreferredSize(new Dimension(480, 85));
        topPanel.setBackground(Color.white);
        topPanel.add(bar, BorderLayout.NORTH);
        topPanel.add(df, BorderLayout.SOUTH);
        fpanel.add(topPanel);

        JScrollPane displayTable = createTable(mdl);
        fpanel.add(displayTable, BorderLayout.NORTH); //sdp


        // sdp plot graph..
        //fpanel.add(createDemoPanel(), BorderLayout.SOUTH);

        // create a new JSplitPane to present the interface
        JSplitPane split = new JSplitPane();
        
        Dimension panelSize = new Dimension(485, 0);
        rightPanel.setMinimumSize(panelSize);
        rightPanel.setMaximumSize(panelSize);
        fpanel.setMinimumSize(panelSize);
        
        
        Double dividerLocation = (screenWidth / 1.35);
       // Double dividerLocation = (screenWidth / 1.65);
        Integer divier = dividerLocation.intValue();
        split.setEnabled(false);
        split.setDividerLocation(split.getInsets().right + divier + split.getInsets().left);
        split.setResizeWeight(1.0);
        //split.setTopComponent(df);
        split.setLeftComponent(rightPanel);
        split.setRightComponent(fpanel);
       
        // now we run our action list
        m_vis.run("draw");
        add(split);
    }

    public JPopupMenu setPopUpMenu(Action[] popUpActions) {

        popUpMenu = new JPopupMenu();
        popUpItem = new JMenuItem();

        for (int i = 0; i
                < popUpActions.length; i++) {
            popUpItem = new JMenuItem(popUpActions[i]);
            popUpMenu.add(popUpItem);
            if (i == 1) {
                popUpMenu.addSeparator();
            }
            display.setComponentPopupMenu(popUpMenu);
        }
        return popUpMenu;
    }

    public JPopupMenu setTablePopUpMenu(Action[] popUpActions) {
        tablePopupMenu = new JPopupMenu();
        tablePopupItem = new JMenuItem();

        for (int i = 0; i < popUpActions.length; i++) {
            tablePopupItem = new JMenuItem(popUpActions[i]);
            tablePopupMenu.add(tablePopupItem);

            if (i == 0) {
                tablePopupMenu.addSeparator();
            }
            display_table.setComponentPopupMenu(tablePopupMenu);
        }
        return tablePopupMenu;
    }

    private JScrollPane createTable(final MyTableModel mdl) {
        ProgressCellRenderer rdr = new ProgressCellRenderer();
        display_table = new JTable(mdl);
        display_table.setBackground(Color.white);
        display_table.setAutoscrolls(true);
        display_table.setDefaultRenderer(Object.class, new MyTableCellRender());
        display_table.setAutoCreateRowSorter(true);
        display_table.getTableHeader().setReorderingAllowed(false);

        TableColumnModel tcl = display_table.getColumnModel();
        // 5 is the row of table to have color progress bar
        tcl.getColumn(5).setCellRenderer(rdr);

        scrollPane = new JScrollPane(display_table);
        scrollPane.setPreferredSize(new Dimension(480, 340));
        display_table.setFillsViewportHeight(true);
        percentageList = new ArrayList();
        postTimeList = new ArrayList();
        clickedUserList = new ArrayList();

        ListSelectionModel model = display_table.getSelectionModel();
        model.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        model.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {

                if (!e.getValueIsAdjusting()) {
                    int[] totalselectedRowCount = display_table.getSelectedRows();
                    int z = totalselectedRowCount.length;

                    for (int i = 0; i < z; i++) {
                        String tmpUser = String.valueOf(display_table.getValueAt(totalselectedRowCount[i], 2));
                        String tmpPercentage = String.valueOf(display_table.getValueAt(totalselectedRowCount[i], 5));
                        String tmpTime = String.valueOf(display_table.getValueAt(totalselectedRowCount[i], 4));

                        double tempPercentage = Double.parseDouble(tmpPercentage);
                        if(tempPercentage < 0){
                            tempPercentage = 0;
                        }
                        percentageList.add(tempPercentage);
                        postTimeList.add(tmpTime);
                        clickedUserList.add(tmpUser);

                        /* if (clickedUserList.contains(tmpUser)) {
                        clickedUserList.remove(tmpUser);
                        clickedUserList.remove(tmpPercentage);
                        clickedUserList.remove(tmpTime);
                        } else {
                        percentageList.add(tmpPercentage);
                        postTimeList.add(tmpTime);
                        clickedUserList.add(tmpUser);
                        }*/

                    }
                }
            }
        });
        int tableSize = display_table.getRowCount();
        avgPercentageAxn = new TableActions("Average Match", "averageMatch", percentageList, clickedUserList, mdl, tableSize, null);
        allpostTimeGraphAxn = new TableActions("Post Time Graph", "postTimeGraph", postTimeList, clickedUserList, mdl, tableSize, fpanel);
        display_table.add(setTablePopUpMenu(new Action[]{allpostTimeGraphAxn, avgPercentageAxn}));

        return scrollPane;
    }

    public void setNewAction(Action newAxn) {
        bar.add(newAxn);
    }

    public void setChartAction(Action chartAxn) {
        bar.add(chartAxn);
        bar.addSeparator();
    }

    public void setThreadAction(Action threadAxn) {
        bar.add(threadAxn);
    }

    public void setFriendAction(Action friendAxn) {
        bar.add(friendAxn);
    }

    public void setTimeAction(Action timeAxn) {
        bar.add(timeAxn);
    }

    public void setNameAction(Action nameAxn) {
        bar.add(nameAxn);
    }

    public void setStylometricAction(Action stylometricAxn) {
        bar.add(stylometricAxn);
        bar.addSeparator();
    }

    public void setExitAction(Action exitAxn) {
        bar.add(exitAxn);
    }

    /**
     * Set node text colors
     */
    public static class TextColorAction extends ColorAction {

        public TextColorAction(String group) {
            super(group, VisualItem.TEXTCOLOR, ColorLib.gray(0));
            add("_hover", ColorLib.rgb(255, 255, 255));
            add(VisualItem.FIXED, ColorLib.rgb(0, 0, 0));
        }
    } // end of inner class TextColorAction

    public void setGraph(Graph graph) {

        LabelRenderer r = new LabelRenderer(label);
        r.setHorizontalAlignment(Constants.CENTER);
        r.setRoundedCorner(8, 8);
        m_vis.setRendererFactory(new DefaultRendererFactory(r));

        VisualGraph vg = m_vis.addGraph(treeGraph, graph);
        m_vis.setValue(edges, null, VisualItem.INTERACTIVE, Boolean.FALSE);
        for (int i = 0; i < vg.getNodeCount(); i++) {
            VisualItem f = (VisualItem) vg.getNode(i);
            m_vis.getGroup(Visualization.FOCUS_ITEMS).setTuple(f);
            f.setFixed(false);
        }
    }

    /**
     * On mouse hover over the nodes, it displays respective member's ID and
     * increase the size of node. Similarly, when the mouse is removed from
     * the node, it will retain its original size.
     */
    public class HoverNode extends ControlAdapter {

        @Override
        public void itemEntered(VisualItem item, MouseEvent e) {

            if (item instanceof NodeItem) {
                //System.out.println("Item: " + item);
                Visualization vis = item.getVisualization();
                item.setSize(1.5);
                Display d = vis.getDisplay(0);
                d.setToolTipText((vis.getSourceTuple(item)).getString("MemberID"));
            }
        }

        @Override
        public void itemExited(VisualItem item, MouseEvent e) {

            if (item instanceof NodeItem) {
                item.setSize(1);
                Visualization vis = item.getVisualization();
                Display d = vis.getDisplay(0);
                d.setToolTipText(null);
                vis.run("draw");
            }
        }
    }

    /**
     * When a node is clicked, the ID of respective user is stored in ArrayList
     */
    public class itemClick extends ControlAdapter {

        @Override
        public void itemClicked(VisualItem item, MouseEvent e) {

            String userID;
            String userName = item.getString(label);

            if (item.canGetString("MemberID")) {
                userID = item.getString("MemberID");
            } else {
                userID = item.getString("BoardID");
            }

            if (userIDList.contains(userID)) {
                int tempUserIDIndex = userIDList.indexOf(userID);
                int tempUserNameIndex = userNameList.indexOf(userName);
                userIDList.remove(tempUserIDIndex);
                userNameList.remove(tempUserNameIndex);

            } else {
                userIDList.add(userID);
                userNameList.add(userName);
            }
        }
    }

    // ------------------------------------------------------------------------
    // Main and demo methods
    public static void main(String[] args) throws DataIOException, SQLException {
        UILib.setPlatformLookAndFeel();
        Graph graph;
        //making connection with database
        con = DBConnection.getDBConnection();
        //ConnectionFactory cfac = new ConnectionFactory();
        datasource = ConnectionFactory.getDatabaseConnection(con);

        String nodeQuery = "SELECT MemberID, Name FROM tbl_member_all";
        //String nodeQuery = "SELECT * from node";
        tableNodes = datasource.getData(nodeQuery);

        String edgeQuery = "SELECT BoardID, FriendBoardID FROM tbl_member_friend_copy where BoardID != '374'";
        //String edgeQuery = "SELECT * FROM edge";
        tableEdges = datasource.getData(edgeQuery);

        graph = new Graph(tableNodes, tableEdges, true, "MemberID", "BoardID", "FriendBoardID");
        //graph = new Graph(tableNodes, tableEdges, true, "Id", "Sid", "Tid");
        frame = demo(graph);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //frame.setSize(maxBounds.width, maxBounds.height);
    }

    public static JFrame demo(Graph g) {
        final BoardGraphView view = new BoardGraphView(g);
        // launch window
        mainFrame = new JFrame("Alias Detector");

        mainFrame.setContentPane(view); 
        mainFrame.pack();
        mainFrame.setVisible(true);

        mainFrame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowActivated(WindowEvent e) {
                view.m_vis.run("layout");
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                view.m_vis.cancel("layout");
            }
        });

        return mainFrame;
    }
} // end

